home *** CD-ROM | disk | FTP | other *** search
/ Workbench Design / WB Collection.iso / workbench werkzeuge / memory & system tools / priman / source / main.c < prev    next >
C/C++ Source or Header  |  1996-04-07  |  19KB  |  587 lines

  1. /*
  2.  *        Task Priority Manager
  3.  *        Copyright 1993, 1994 Barry McConnell
  4.  *        bmccnnll@tcd.ie
  5.  *
  6.  *        The main program loop
  7.  
  8.  *        Set tab stops to 4 when editing this file.
  9.  */
  10.  
  11. #define MAIN  /* tells header file to define (as opposed to declare) variables */
  12. #include "PriMan.h"
  13.  
  14. long __oslibversion = 36;  /* tell SAS/C what library versions we need */
  15. static UBYTE version[] = "$VER: PriMan "VERSION" ("DATE")";  /* version string */
  16.  
  17. /*
  18.  *        First we have some global variables. These would normally go in the
  19.  *        header file, but it's easier to define structures with initial data
  20.  *        here. First is the broker structure for the Commodity interface.
  21.  */
  22. struct NewBroker newBroker =
  23.     {
  24.     NB_VERSION,
  25.     "PriMan",
  26.     "PriMan "VERSION" by Barry McConnell",
  27.     "Task priority manager",
  28.     NBU_UNIQUE | NBU_NOTIFY,
  29.     COF_SHOW_HIDE,
  30.     0, 0, 0
  31.     };
  32.  
  33. /*
  34.  *        The starting point for PriMan. First we need to parse the ToolTypes and
  35.  *        initialiase some variables. Then we set up the Commodity interface if
  36.  *        necessary. And finally, we handle all the possible messages that can
  37.  *        arrive at our ports. SAS/C kindly opens all the libraries for us, so we
  38.  *        don't need to worry about that...
  39.  */
  40. void main(int argc, char *argv[])
  41.     {
  42.     BOOL    more,                        /* might be more messages waiting for us    */
  43.             help;                        /* user has asked for help at startup time    */
  44.  
  45.     ULONG    signal,                        /* signal type received                        */
  46.             class,                        /* message type received                    */
  47.             winSignal,                    /* window port signal bit                    */
  48.             appSignal,                    /* AppIcon port signal bit                    */
  49.             cxSignal;                    /* Commodities port signal bit                */
  50.  
  51.     UWORD    shift,                        /* Shift key was pressed                    */
  52.             ctrl;                        /* Ctrl key was pressed                        */
  53.  
  54.     WORD    code,                        /* code within message structure            */
  55.             key,                        /* VANILLAKEY code, converted to lower-case    */
  56.             raw;                        /* RAWKEY code                                */
  57.  
  58.     struct Message            *message;        /* message received from port            */
  59.     struct IntuiMessage        *imsg;            /* GadTools-parsed message                */
  60.     struct AmigaGuideMsg    *amsg;            /* AmigaGuide-parsed message            */
  61.     struct Window            *window;        /* window the message refers to            */
  62.     struct Gadget            *selectedGad;    /* gadget the message refers to            */
  63.  
  64.     /*
  65.      *        Template for the error messages PriMan can give before exiting.
  66.      */
  67.     struct EasyStruct errorMessage =
  68.         {
  69.         sizeof(struct EasyStruct),
  70.         0,
  71.         "PriMan Fatal Error",
  72.         "%s",
  73.         "Okay"
  74.         };
  75.  
  76.     /*
  77.      *        Check what OS version we're running under, so we can take advantage
  78.      *        of some new 3.x features where possible.
  79.      */
  80.     osver = SysBase -> LibNode.lib_Version;
  81.  
  82.     /*
  83.      *        Create the three message ports that PriMan needs to talk to the
  84.      *        outside world with, and note their signal bits.
  85.      */
  86.     winPort        = CreateMsgPort();
  87.     appPort        = CreateMsgPort();
  88.     cxPort        = CreateMsgPort();
  89.     winSignal    = 1L << winPort -> mp_SigBit;
  90.     appSignal    = 1L << appPort -> mp_SigBit;
  91.     cxSignal    = 1L << cxPort -> mp_SigBit;
  92.  
  93.     /*
  94.      *        We need to get the TextAttr structures to point to their font names.
  95.      */
  96.     propTA.ta_Name = propName;
  97.     monoTA.ta_Name = monoName;
  98.  
  99.     /*
  100.      *        Here we set up the defaults for all the settings variables, in case
  101.      *        the user doesn't change them. Note that the font information get set
  102.      *        to 0 on startup by the compiler.
  103.      */
  104.     winLeft        = winTop = -1;
  105.     winWidth    = winHeight = 0;
  106.     iconLeft    = iconTop = priority = 0;
  107.     confirm        = commodity = popup = iconify = TRUE;
  108.     refresh        = SMARTWINDOW;
  109.     open        = DEFAULTSCREEN;
  110.     strcpy(hotkey, "control alt p");
  111.     help        = FALSE;  /* default is no immediate online help */
  112.  
  113.     /*
  114.      *        When being iconfied, we use another icon file, which gets filled in
  115.      *        with PriMan's icon imagery below if possible. This call should never
  116.      *        fail, so I don't do any checking on it.
  117.      */
  118.     wbIcon = GetDefDiskObject(WBTOOL);
  119.  
  120.     /*
  121.      *        Before parsing the ToolTypes, we must open PriMan's .info file. If
  122.      *        we're running from the Workbench (argc is 0), we take the filename
  123.      *        from the WBStartup structure. From the Shell, we use argv[0]. We
  124.      *        then prefix this by PROGDIR: to form a full pathname.
  125.      */
  126.     sprintf(myName, "PROGDIR:%s",
  127.             argc ? argv[0] : ((struct WBStartup *)argv) -> sm_ArgList -> wa_Name);
  128.     if (myIcon = GetDiskObject(myName))
  129.         {
  130.         if (myIcon -> do_Type != WBTOOL)
  131.             {
  132.             /*
  133.              *        Sanity failure! We've found a .info file, but it doesn't
  134.              *        really belong to PriMan.
  135.              */
  136.             FreeDiskObject(myIcon);
  137.             myIcon = NULL;
  138.             }
  139.         else
  140.             {
  141.             /*
  142.              *        The correct .info file is open, so we first parse the
  143.              *        ToolTypes from it, and then copy the imagery across to the
  144.              *        AppIcon.
  145.              */
  146.             HandleToolTypes(myIcon -> do_ToolTypes, &help);
  147.  
  148.             wbIcon -> do_Gadget.Flags = myIcon -> do_Gadget.Flags;
  149.             wbIcon -> do_Gadget.Width = myIcon -> do_Gadget.Width;
  150.             wbIcon -> do_Gadget.Height = myIcon -> do_Gadget.Height;
  151.             wbIcon -> do_CurrentX = iconLeft;
  152.             wbIcon -> do_CurrentY = iconTop;
  153.             wbIcon -> do_Gadget.GadgetRender = myIcon -> do_Gadget.GadgetRender;
  154.             wbIcon -> do_Gadget.SelectRender = myIcon -> do_Gadget.SelectRender;
  155.             }
  156.         }
  157.  
  158.     /*
  159.      *        If we're running from the Shell, there may be additional arguments.
  160.      */
  161.     if (argc)
  162.         {
  163.         /*
  164.          *        It's possible the user is just enquiring as to what PriMan is
  165.          *        all about (first argument is a question mark), so we print out
  166.          *        some info and exit.
  167.          */
  168.         if (argc > 1 && !strcmp(argv[1], "?"))
  169.             {
  170.             Print(    "PriMan " VERSION " by Barry McConnell - The Task Priority Manager\n" \
  171.                     "Usage: PriMan [COMMODITY=YES|NO] [CX_POPUP=YES|NO] [CX_POPKEY=hotkey]\n" \
  172.                     "              [CX_PRIORITY=priority] [LEFT=left edge] [TOP=top edge]\n" \
  173.                     "              [WIDTH=width] [HEIGHT=height] [GADFONT=font name]\n" \
  174.                     "              [GADSIZE=font size] [LISTFONT=font name] [LISTSIZE=font size]\n" \
  175.                     "              [REFRESH=SMART|SIMPLE] [SCREEN=DEFAULT|FRONT] [ICONLEFT=left edge]\n"\
  176.                     "              [ICONTOP=top edge] [CONFIRM=YES|NO] [ICONIFY=YES|NO]\n" \
  177.                     "              [TOOLPRI=task priority]\n" \
  178.                     "Type \"PriMan HELP\" to get AmigaGuide help.\n");
  179.             error = ALL_OKAY;
  180.             }
  181.         else
  182.             HandleToolTypes(argv, &help);
  183.         }
  184.  
  185.     /*
  186.      *        Now we install ourselves as a Commodity, assuming the error variable
  187.      *        wasn't set above. If there is an existing PriMan running as a
  188.      *        Commodity, error will be set here, and the main loop below will fall
  189.      *        out immediately.
  190.      */
  191.     if (!error)
  192.         {
  193.         newBroker.nb_Port = cxPort;
  194.         newBroker.nb_Pri = priority;
  195.         if (commodity)
  196.             SetupCommodity();
  197.     
  198.         if (!error)
  199.             {
  200.             /*
  201.              *        Since pos gets initialised to 0 by the compiler, and there
  202.              *        won't actually be a task selected to start with, we change
  203.              *        it to -1 here. This isn't strictly necessary (since some
  204.              *        code later on does this for us), but it tells the function
  205.              *        which creates the main window's gadgetry to disable some
  206.              *        buttons when they are being created, so we avoid an initial
  207.              *        "flashing" the first time the window is opened.
  208.              */
  209.             pos = -1;
  210.         
  211.             /*
  212.              *        Here we define what happens on startup. If the user does not
  213.              *        want us to "popup when launched", and we are running as a
  214.              *        Commodity or can be iconified, then we don't open a window,
  215.              *        and instead create an AppIcon if necessary. Otherwise, we
  216.              *        must open the main window.
  217.              */
  218.             if (!popup && (iconify || commodity))
  219.                 Iconify();
  220.             else
  221.                 Show();
  222.  
  223.             if (!error)
  224.                 /*
  225.                  *        If the user wants online help, we wait until here to
  226.                  *        fire up AmigaGuide (in case something went wrong setting
  227.                  *        stuff up above).
  228.                  */
  229.                 if (help)
  230.                     Help();
  231.             }
  232.         }
  233.  
  234.     /*
  235.      *        This is the heart of PriMan. As long as nothing has gone wrong, we
  236.      *        go round in a loop waiting for a message from any of our three
  237.      *        ports, the AmigaGuide port (if applicable), or a Ctrl-C/F signal,
  238.      *        handle that message, then loop back.
  239.      */
  240.     while (!error)
  241.         {
  242.         signal = Wait(winSignal | appSignal | cxSignal | guideSignal |
  243.                       SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F);
  244.         do
  245.             {
  246.             /*
  247.              *        We use the "more" variable to let us know when to stop
  248.              *        checking each port for more messages. If it's still set to
  249.              *        FALSE at the end of the loop, it means all ports are now
  250.              *        empty, and we can go back to sleep.
  251.              */
  252.             more = FALSE;
  253.  
  254.             /*
  255.              *        If we get a Ctrl-C signal, we immediately abort the
  256.              *        while loop, without checking the other ports.
  257.              */
  258.             if (signal & SIGBREAKF_CTRL_C)
  259.                 {
  260.                 error = ALL_OKAY;
  261.                 break;
  262.                 }
  263.  
  264.             /*
  265.              *        A Ctrl-F signal means we should make ourselves visible.
  266.              */
  267.             if (signal & SIGBREAKF_CTRL_F)
  268.                 Show();
  269.  
  270.             /*
  271.              *        The only possible message from the AppIcon's port will
  272.              *        tell us to wake up, so if we receive it, we open the
  273.              *        main window, and reply to the message.
  274.              */
  275.             if (signal & appSignal && (message = GetMsg(appPort)))
  276.                 {
  277.                 ReplyMsg(message);
  278.                 Show();
  279.                 more = TRUE;
  280.                 }
  281.  
  282.             /*
  283.              *        We need to handle lots of difference cases if we get a
  284.              *        message from the Commodities port. We might need to
  285.              *        open (or bring to the front) the main window if the
  286.              *        Show button was pressed in Exchange, or the hotkey was
  287.              *        pressed, or another PriMan tried installing itself as a
  288.              *        Commodity. We might need to hide our windows if the Hide
  289.              *        button was pressed in Exchange. And finally, if Exchange
  290.              *        sends us a Kill message, we must close down. Any other
  291.              *        message types are ignored.
  292.              */
  293.             if (signal & cxSignal && (message = GetMsg(cxPort)))
  294.                 {
  295.                 switch (class = CxMsgType((CxMsg *)message))
  296.                     {
  297.                     case CXM_COMMAND:
  298.                         switch (CxMsgID((CxMsg *)message))
  299.                             {
  300.                             case CXCMD_APPEAR:
  301.                             case CXCMD_UNIQUE:
  302.                                 Show();
  303.                                 break;
  304.  
  305.                             case CXCMD_DISAPPEAR:
  306.                                 Hide();
  307.                                 break;
  308.  
  309.                             case CXCMD_KILL:
  310.                                 error = ALL_OKAY;
  311.                                 break;
  312.                             }
  313.                         break;
  314.  
  315.                     case CXM_IEVENT:  /* user pressed hotkey */
  316.                         Show();
  317.                         break;
  318.                     }
  319.                 ReplyMsg(message);
  320.                 more = TRUE;
  321.                 }
  322.  
  323.             /*
  324.              *        Here is a very basic AmigaGuide handler. We only check for
  325.              *        one type of message and ignore all the rest - no error
  326.              *        handling is performed. The message we need to check for is
  327.              *        ActiveToolID: this means the process spawned in the Help()
  328.              *        function has successfully opened the PriMan.guide file, and
  329.              *        is waiting for further instructions. We actually call Help()
  330.              *        again in this case, as now that we have a valid handle on
  331.              *        the guide file, that function will jump to the first node
  332.              *        in it for us.
  333.              */
  334.             if (signal & guideSignal && (amsg = GetAmigaGuideMsg(guideHandle)))
  335.                 {
  336.                 if (amsg -> agm_Type == ActiveToolID)
  337.                     Help();
  338.                 ReplyAmigaGuideMsg(amsg);
  339.                 more = TRUE;
  340.                 }
  341.  
  342.             /*        This is the fun bit. A message to our window port can
  343.              *        come from either window. The easiest thing to do is to
  344.              *        simply pass it onto a separate procedure. But first,
  345.              *        there is a little bit of complicated stuff involving
  346.              *        window resizing...
  347.              */
  348.             if (signal & winSignal && (imsg = GT_GetIMsg(winPort)))
  349.                 {
  350.                 /*
  351.                  *        Make a note of the important information in the
  352.                  *        message.
  353.                  */
  354.                 key = raw = 0;
  355.                 class = imsg -> Class;
  356.                 selectedGad = imsg -> IAddress;
  357.                 code = imsg -> Code;
  358.                 shift = imsg -> Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT);
  359.                 ctrl = imsg -> Qualifier & IEQUALIFIER_CONTROL;
  360.                 window = imsg -> IDCMPWindow;
  361.  
  362.                 /*
  363.                  *        There are several events which must be handled before
  364.                  *        replying to the message.
  365.                  */
  366.                 switch (class)
  367.                     {
  368.                     /*
  369.                      *        If we get a SIZEVERIFY message, we need to remove
  370.                      *        all the GadTools gadgets before we allow the user
  371.                      *        to move the size gadget. This will prevent Intuition
  372.                      *        doing any unnecessary refreshing, and will also
  373.                      *        ensure the window's borders don't get clobbered.
  374.                      */
  375.                     case IDCMP_SIZEVERIFY:
  376.                         RemoveGList(mainWindow, mainGads, -1);
  377.                         window = NULL;
  378.                         break;
  379.  
  380.                     /*
  381.                      *        A NEWSIZE message generally means all the gadgets
  382.                      *        must be deallocated, recreated, and added back into
  383.                      *        the window. However, if the window size did not
  384.                      *        actually change, there is no need to do this, and
  385.                      *        instead we just quietly add back in the existing
  386.                      *        gadget list (which didn't actually get deallocated
  387.                      *        on SIZEVERIFY).
  388.                      */
  389.                     case IDCMP_NEWSIZE:
  390.                         if (winWidth == mainWindow -> Width && winHeight == mainWindow -> Height)
  391.                             AddGList(mainWindow, mainGads, ~0, -1, NULL);
  392.                         else
  393.                             {
  394.                             GetListTop();  /* so we can restore it later */
  395.                             FreeGadgets(mainGads);
  396.                             mainGads = NULL;
  397.                             OpenMainWindow();
  398.                             }
  399.                         window = NULL;
  400.                         break;
  401.  
  402.                     /*
  403.                      *        In addition, while we could pass on the INTUITICKS
  404.                      *        messages to the appropriate procedures, these
  405.                      *        actually do nothing with this event, so in order
  406.                      *        not to waste CPU time, we ignore this event by
  407.                      *        setting the window variable to NULL (this is also
  408.                      *        done for the two events above, as they have been
  409.                      *        appropriately handled right here).
  410.                      */
  411.                     case IDCMP_INTUITICKS:
  412.                         window = NULL;
  413.                         break;
  414.  
  415.                     /*
  416.                      *        We want to do a little mapping of VANILLAKEY codes.
  417.                      *        If Shift is being pressed, we must set bit 5 of the
  418.                      *        keycode to convert it to lower-case. For Ctrl, we
  419.                      *        ensure both bits 5 and 6 are set. The end result is
  420.                      *        a lower-case version of any keypress handled by this
  421.                      *        Intuition event. (Check an ASCII table to see how
  422.                      *        keypresses come out with these modifiers!)
  423.                      */
  424.                     case IDCMP_VANILLAKEY:
  425.                         key = code | (shift ? 32 : 0) | (ctrl ? 96 : 0);
  426.                         break;
  427.  
  428.                     /*
  429.                      *        RAWKEY codes don't need mapping, and in fact we only
  430.                      *        use these for the Help key!
  431.                      */
  432.                     case IDCMP_RAWKEY:
  433.                         raw = code;
  434.                         break;
  435.                     }
  436.  
  437.                 GT_ReplyIMsg(imsg);
  438.                 more = TRUE;
  439.  
  440.                 /*
  441.                  *        Now we despatch the message to another function if
  442.                  *        it is still necessary (i.e. the window variable
  443.                  *        wasn't cleared above).
  444.                  */
  445.                 if (window == mainWindow)
  446.                     HandleMainWindow(class, code, key, raw, shift, ctrl, selectedGad);
  447.                 else if (window == setWindow)
  448.                     HandleSettingsWindow(class, code, key, raw, shift, selectedGad);
  449.                 }
  450.             }
  451.         while (more);  /* could be more messages waiting for us */
  452.         }
  453.  
  454.     /*
  455.      *        If we've got this far, either something bad happened, or the "all
  456.      *        okay" error condition was raised (meaning the user wanted us to
  457.      *        quit). We need to shut down windows, free up gadgets, deallocate
  458.      *        memory, and free up other system stuff. Then - if necessary - an
  459.      *        error requester is displayed.
  460.      */
  461.     CloseSettingsWindow();
  462.     CloseMainWindow();
  463.     FreeRemember(&memoryKey, TRUE);
  464.  
  465.     DeleteCxObjAll(broker);
  466.     FreeAslRequest(propFontReq);
  467.     FreeAslRequest(monoFontReq);
  468.  
  469.     if (guideHandle)
  470.         CloseAmigaGuide(guideHandle);
  471.     CloseLibrary(AmigaGuideBase);
  472.  
  473.     if (appIcon)
  474.         RemoveAppIcon(appIcon);
  475.     if (wbIcon)
  476.         FreeDiskObject(wbIcon);
  477.     if (myIcon)
  478.         FreeDiskObject(myIcon);
  479.  
  480.     WipePort(winPort);
  481.     WipePort(appPort);
  482.     WipePort(cxPort);
  483.  
  484.     switch (error)  /* there does not necessarily have to be one */
  485.         {
  486.         case LOCK_ERROR:
  487.             SimpleRequest(&errorMessage, "Can't lock default public screen.");
  488.             break;
  489.         case VISINFO_ERROR:
  490.             SimpleRequest(&errorMessage, "Can't get VisualInfo for this screen.");
  491.             break;
  492.         case FONT_ERROR:
  493.             SimpleRequest(&errorMessage, "Can't open your selected fonts.");
  494.             break;
  495.         case GADGET_ERROR:
  496.             SimpleRequest(&errorMessage, "Can't create list of gadgets.\n(Out of memory?)");
  497.             break;
  498.         case MAIN_ERROR:
  499.             SimpleRequest(&errorMessage, "Can't open main window.\n(Out of memory?)");
  500.             break;
  501.         case TASK_ERROR:
  502.             SimpleRequest(&errorMessage, "Can't create list of tasks.\n(Out of memory?)");
  503.             break;
  504.         case SETTINGS_ERROR:
  505.             SimpleRequest(&errorMessage, "Can't open settings window.\n(Out of memory?)");
  506.             break;
  507.         case CX_ERROR:
  508.             SimpleRequest(&errorMessage, "Can't set up Commodity interface.");
  509.             break;
  510.         case MENU_ERROR:
  511.             SimpleRequest(&errorMessage, "Can't create menus.\n(Out of memory?)");
  512.             break;
  513.         }
  514.     }
  515.  
  516.  
  517. /*
  518.  *        Since the user can pass settings information in two ways (ToolTypes and
  519.  *        Shell arguments), we put the code to parse them in a separate function.
  520.  *        It takes in an array of ToolTypes (from the .info file) or Shell
  521.  *        arguments (from argv[]) and examines their contents using ArgInt() or
  522.  *        ArgString(). If HELP is one of those keywords, it sets the help flag
  523.  *        passed in.
  524.  */
  525. void HandleToolTypes(char **tools, BOOL *help)
  526.     {
  527.     /*
  528.      *        For the numeric settings, if a ToolType can't be found, we use the
  529.      *        existing value of the settings variable. (Which will either be the
  530.      *        internal default, or - if we're examining Shell arguments - the
  531.      *        ToolType value from the last time this function was called.)
  532.      */
  533.     winLeft            = (WORD)ArgInt(tools, "LEFT", winLeft);
  534.     winTop            = (WORD)ArgInt(tools, "TOP", winTop);
  535.     winWidth        = (WORD)ArgInt(tools, "WIDTH", winWidth);
  536.     winHeight        = (WORD)ArgInt(tools, "HEIGHT", winHeight);
  537.     propTA.ta_YSize    = (UWORD)ArgInt(tools, "GADSIZE", propTA.ta_YSize);
  538.     monoTA.ta_YSize    = (UWORD)ArgInt(tools, "LISTSIZE", monoTA.ta_YSize);
  539.     iconLeft        = (WORD)ArgInt(tools, "ICONLEFT", iconLeft);
  540.     iconTop            = (WORD)ArgInt(tools, "ICONTOP", iconTop);
  541.     priority        = (BYTE)ArgInt(tools, "CX_PRIORITY", priority);
  542.  
  543.     /*
  544.      *        The string settings are handled similarly.
  545.      */
  546.     strcpy(propName, ArgString(tools, "GADFONT", propName));
  547.     strcpy(monoName, ArgString(tools, "LISTFONT", monoName));
  548.     strncpy(hotkey, ArgString(tools, "CX_POPKEY", hotkey), MaxHotkey);
  549.  
  550.     /*
  551.      *        The YES/NO settings follow. Since the defaults are all YES, we bias
  552.      *        towards this, and only allow a NO if the first letter is 'n'. (So
  553.      *        "xyz" would be YES.)
  554.      */
  555.     confirm        = (ArgString(tools, "CONFIRM", confirm ? "Y" : "N")[0] & ~32) != 'N';
  556.     commodity    = (ArgString(tools, "COMMODITY", commodity ? "Y" : "N")[0] & ~32) != 'N';
  557.     popup        = (ArgString(tools, "CX_POPUP", popup ? "Y" : "N")[0] & ~32) != 'N';
  558.     iconify        = (ArgString(tools, "ICONIFY", iconify ? "Y" : "N")[0] & ~32) != 'N';
  559.  
  560.     /*
  561.      *        Our defaults for Window Type and Open On are SMART and DEFAULT,
  562.      *        respectively. As above, we are biased, and only change these if the
  563.      *        user enters exactly the text SIMPLE or FRONT.
  564.      */
  565.     refresh    = !Compare(ArgString(tools, "REFRESH", refresh == SMARTWINDOW ? "SMART" : "SIMPLE"), "SIMPLE");
  566.     open    = !Compare(ArgString(tools, "SCREEN", open == DEFAULTSCREEN ? "DEFAULT" : "FRONT"), "FRONT");
  567.  
  568.     /*
  569.      *        Here we handle the TOOLPRI setting. (This may already have been
  570.      *        done if we were launched from Workbench.) We examine our own task
  571.      *        structure to see what priority we are at currently, and "change" to
  572.      *        that if no ToolType was given.
  573.      */
  574.     SetTaskPri(FindTask(NULL), (BYTE)ArgInt(tools, "TOOLPRI", FindTask(NULL) -> tc_Node.ln_Pri));
  575.  
  576.     /*
  577.      *        Finally, if the user wants help, we set a flag to ensure he gets it
  578.      *        later. We don't call Help() ourselves now since if there was an
  579.      *        error during startup, we'd run into real trouble trying to kill the
  580.      *        AmigaGuide process while it was doing its thing!
  581.      *
  582.      *        If the help flag was already set, obviously we don't need to do the
  583.      *        test for the HELP keyword again.
  584.      */
  585.     *help = *help || FindToolType(tools, "HELP");
  586.     }
  587.